/*
  FileName : MainUnit.c
  Modified on 2015.10.9 by WFL.
  Description:
    This is the main unit of GPS_V20 project.

function：
	1.USART Data transmission
	2.Line information searching according to GPS data.
	3.RTC
	4.USB transmission
	5.HEX handler
	6.FLASH read and write
	7.LED display
	8.File system
	9.interaction with MMI
*/


//software Version and Date
#define SOFT_VER  0x0201
#define SOFT_DATE 0x20160707

#include <std.h>
#include <hwi.h>			//for HWI_ definition
#include <string.h>
#include "DSP281x_Device.h"
#include "GpsV101Cfg.h"
#include "MainVar.h"
#include "GPS_Location_Handle.h"
#include "GPS_Region.h"
#include "GPS_QieHuan.h"
#include "MainUnitFunc.h"
#include "CirGpsCommand.h"
#include "GPS_SatelliteData.h"
#include "GPS_RoadLockHandle.h"
#include "GPS_PRE_NXT_ST.h"
#include "GPS_PublicPositionData.h"
#include "GPS_MMITransmitdata.h"
#include "GPS_Prototypes.h"

//////////////////////////////////////////////////////////////////////////////////
//                 LNK module :  load from FLASH to RAM
//////////////////////////////////////////////////////////////////////////////////

volatile Uns PrdDiv;
volatile Uns PowOnFlag;
volatile Uns GpsDataFlag = 'V';



void main(void)
{
  Uns i;

  memcpy(&FuncsMap2H0SARam_runstart,
         &FuncsMap2H0SARam_loadstart,
         &FuncsMap2H0SARam_loadend - &FuncsMap2H0SARam_loadstart);

  EALLOW;
  memcpy(&hwi_vec_runstart,
         &hwi_vec_loadstart,
         &hwi_vec_loadend - &hwi_vec_loadstart);
  EDIS;
  asm("  RPT #150 || NOP");

  InitMainVar();

  PowOnFlag = 1;

  // PLL, WatchDog, enable Peripheral Clocks
  InitSysCtrl();
  InitGpio();
  Sci_InitPort();
  InitPieCtrl();
  IER = 0x0000;
  IFR = 0x0000;
  InitFlash();
  InitAdc();
// Enable XINT1-HC in the PIE : Group 1 interrupt 4
  PieCtrlRegs.PIEIER1.bit.INTx4 = 1;
// Enable XINT2-DC in the PIE : Group 1 interrupt 5
  //PieCtrlRegs.PIEIER1.bit.INTx5 = 1;
// Enable TINT0 in the PIE: Group 1 interrupt 7
  //PieCtrlRegs.PIEIER1.bit.INTx7 = 1;
// Enable CPU INT1 which is connected to CPU-Timer 0:
  IER |= M_INT1;
  
  InitEv();
  // Enable PIE group 2 interrupt 4 for T1PINT
  PieCtrlRegs.PIEIER2.bit.INTx4 = 1;
  // Enable PIE group 3 interrupt 1 for T2PINT
  PieCtrlRegs.PIEIER3.bit.INTx1 = 1;
  IER |= M_INT2;
  IER |= M_INT3;

  InitXintf();

  //KickDog();
  FEED_DOG;
  //此处复位 USB：
  ResetUSB;
  for (i = 0; i < 100; i++)
    asm("  RPT #150 || NOP");
  DeResetUSB;
  for (i = 0; i < 100; i++)
    asm("  RPT #150 || NOP");
  //KickDog();
  FEED_DOG;


  //Test Xternal ram
  TestXMem();
  if (MyInfo.XRamErr)
    while (1){}

  GetUserSettings();
  FEED_DOG;

  if (MyInfo.GsmrMobile == USE_IN_MOBILE){
    if (!Clk_GetMode())
      Clk_SetMode();
	Clk_GetTime(&CurrGpsInfo.Time);
	if (!CheckTimeValid(TIME_SRC_CLK, (Uns *)&CurrGpsInfo.Time)){
      CurrGpsInfo.Time.Second = 00;
	  CurrGpsInfo.Time.Minute = 00;
	  CurrGpsInfo.Time.Hour = 12;
	  CurrGpsInfo.Time.Date = 1;
	  CurrGpsInfo.Time.Month = 1;
	  CurrGpsInfo.Time.Year = 9;
	  Clk_SetTime((DATE_TIME_INFO *)&(CurrGpsInfo.Time));
    }
  }
  else{
    CurrGpsInfo.Time.Second = 00;
	CurrGpsInfo.Time.Minute = 00;
	CurrGpsInfo.Time.Hour = 12;
	CurrGpsInfo.Time.Date = 1;
	CurrGpsInfo.Time.Month = 1;
	CurrGpsInfo.Time.Year = 9;
  }
  memcpy((void *)&(AllTime.SysTime.Second), (void *)&(CurrGpsInfo.Time.Second), 6);

  //XINT1 for HC
  XIntruptRegs.XINT1CR.bit.POLARITY = 0;//High to Low
  XIntruptRegs.XINT1CR.bit.ENABLE = 1;

  //GPS退出复位态
  DeResetGPS;
  //UART退出复位态
  //TL16C752是高电平复位
  DeResetUart;
  //XFlash退出复位态
  DeResetS29;
  asm("  RPT #150 || NOP");

  SetGpsRecInvalid();

  InitUartVars();
  UART_Init(MyInfo.M91_BaudRate);

  InitAllMMIData();

  MyInfo.PrgRdy = 1;
  EnableInterrupts(); 
}
/*
 * SYS_UserInit() is a call by system.
 * reset PrgRdy, PrdDiv.
 */
void SYS_UserInit(void)
{
  MyInfo.PrgRdy = 0;
  PrdDiv = 0;

  memcpy(&Flash28_API_RunStart,
         &Flash28_API_LoadStart,
		 &Flash28_API_LoadEnd - &Flash28_API_LoadStart);
  ////////////////////////////////////////////////////////////////////
  //在 XRAM 中定义的结构需要
  ////////////////////////////////////////////////////////////////////
  pBulkPTDDatas = (volatile struct BULK_PTD_REGS *)&BulkPTDDatas;

  /*** Initialize the .trcdata section before main() ***/
  memcpy(&trcdata_runstart,
         &trcdata_loadstart,
         &trcdata_loadend - &trcdata_loadstart);
}

//Periodic function:2ms
//2ms, ---->10ms
#pragma CODE_SECTION(SYS_PrdFunc0, "FuncsMap2H0SARam")
void SYS_PrdFunc0(void)
{
	//handler for three lights. on, off and flash
	LedHandler();
	//每隔1秒发送一次数据
	PrepareUartDataForPPD();

	//PrdDiv was set to 0 in SYS_UserInit(), and was set to 1 in SYS_MyIdleFunc()
	//in the case of MyInfo.PrgRdy=1.
	switch (PrdDiv)
	{
    	case 0://上电后状态，工作后不再进入此状态
    		TmUsbWait++;
    		if (MyInfo.PrgRdy == 1)
    			FEED_DOG;
    		break;
    	case 1:
    		SerialPortTxs();
    		PrdDiv++;
    		break;
    	case 2:
    		SerialPortRxs();
    		PrdDiv++;
    		break;
    	case 3:
    		StartGPSFunc();
    		PrdDiv++;
    		break;
    	case 4:
    		//GpsValidTm is reset to 0 when A right GPRMC data has been received.
    		//Including 'A' and 'V'.
    		MyInfo.GpsValidTm++;
    		GPS_MMIDataHandler();
    		PrdDiv++;
    		break;
    	case 5:
    		TmFlagIncrease();
    		PrdDiv = 1;
    		break;
    	default:
    		break;
	}
}

//Idle function
void SYS_MyIdleFunc(void)
{
	LgUns i;
	switch (MyInfo.PrgRdy)
	{
		case 1:
    		//维持面点亮1秒：
    		for (i = 0; i < 1000000L; i++)
    			asm("  RPT #150 || NOP");
    		//熄灭面板灯
    		GpioDataRegs.GPADAT.all &= 0xFFE0;//
    		//检测FLASH：必要时初始化
    		TestXFlash();

    		/*
			//Test only
			DataBase.MaxStDist = 500;
			DataBase.MaxStDist_Power2 = DataBase.MaxStDist;
			DataBase.MaxStDist_Power2 *= DataBase.MaxStDist;
			DataBase.DefMaxStLat = 100;
			DataBase.DefMaxStLon = 100;
			DataBase.DefMinStLat = 100;
			DataBase.DefMinStLon = 100;*/
    		//测试读写S29G：
    		/*TestReadWriteXFlash();
			if (MyInfo.FormatF >= 0xFE)
				while (1){}*/

    		OFF_GPS_LED;

    		ReportVer();

    		//初始化 USB
    		Hc_InitHardware();
    		Hc_EnumInternalHub();

    		//此处设置
    		MyInfo.PrgRdy = 2;
    		PrdDiv = 1;
    		//EnableDog();
	  
    		break;
    	case 2:
    		/////////////////////////////////////////////////////////////
    		//for getting out of simulation mode
    		//Tm5Seconds is set to 0 when in the function InitMainVar() called by main()
    		//Tm5Seconds is set to 0 when receive command:Rx_Cmd_SimulateData
    		//Tm5Seconds is set to 0 when MyInfo.SimulateSts == 1
    		if (MyInfo.WorkSts == WORK_STATUS_GPS_SIMULATE)
    		{
    			if (Tm5Seconds > 2000)
    			{
    				HWI_disable();
    				SimulationStateSwitch(1);
					HWI_enable();
    			}
    		}

    		///////////////////////////////////////////////////////////////
    		//for GPS invalid time check.
    		if (MyInfo.WorkSts == WORK_STATUS_NORMAL)
    		{
    			//超过15秒钟没有收到 GPS 数据则 GPS 故障,复位200ms
    			if (MyInfo.GpsValidTm >= 1520)
    			{
    				MyInfo.GpsValidTm = 0;
    				DeResetGPS;
    			}
    			else if ((MyInfo.GpsValidTm >= 1500) && (MyInfo.GpsValidTm < 1510))
    			{
    				if (MyInfo.RoadLocked == ROAD_LOCKED)
    				{
    					HWI_disable();
		    			//MyInfo.RoadLocked = 0;
    					MyInfo.GpsSts = 0;	//GPS_DATA_INVALID;
						SetGpsRecInvalid();	//set PublicPositionData invalid
						MyInfo.GpsLedF = GPS_ERR_ROAD_LOCKED;
						MyInfo.GpsValidTm = 1510;
						HWI_enable();
    				}
    				else
    				{
    					MyInfo.GpsLedF = GPS_ERR_ROAD_NOT_LOCKED;
    				}
    				ResetGPS;	//由于IDLE不能保证运行时间，此处需要一个范围
    			}
    		}
    		////////////////////////////////////////////////////////////
    		////////////////////////////////////////////////////////////
    		HcApp_StatusHandler();
    		if (MyInfo.HcWorkF == 2)
    		{
    			switch (MyInfo.ErrF)
    			{
    				case USB_SAVE_DB_ERR:
    				case USB_SAVE_DB_OK:
    					MyInfo.ErrF = USB_INIT_STATE;
    					HWI_disable();
    					OFF_GPS_LED;
    					OFF_USBU_LED;
    					OFF_USBD_LED;
    					while (1){}
    					//HWI_enable();
    					//break;
    				case USB_SAVING_DB:
    				case USB_DEV_ERR:
    				case USB_NO_DB:
    				default:
    					MyInfo.ErrF = USB_INIT_STATE;
    					MyInfo.HcWorkF = 0;
    					break;
    			}
    		}
    		/////////////////////////////////////////////////////////////////////
    		if (MyInfo.SimulateSts == 1)
    		{
    			Tm5Seconds = 0;
    			HWI_disable();
    			SimulationStateSwitch(0);
    			HWI_enable();
    		}
    		else if (MyInfo.SimulateSts == 3)
    		{
    			HWI_disable();
    			SimulationStateSwitch(1);
    			HWI_enable();
    		}

    		////////////////////////////////////////////////////////////////////
    		//复位按钮：
    		if (!GpioDataRegs.GPBDAT.bit.GPIOB10)
    		{
    			Sw1Tm = 0;
    			while ((!GpioDataRegs.GPBDAT.bit.GPIOB10) && (Sw1Tm < 100)){}
    			if (!GpioDataRegs.GPBDAT.bit.GPIOB10)
    			{
    				HWI_disable();
    				OFF_GPS_LED;
    				OFF_USBU_LED;
    				OFF_USBD_LED;
    				while (1){}
    			}
    		}
    		break;
    	default:
    		break;
	}
}

//task running is controlled by SEM_GpsData.
//This searching task runs only when GPS data valid.
#pragma CODE_SECTION(SYS_TskFunc_GpsDataHandler, "FuncsMap2H0SARam")
void SYS_TskFunc_GpsDataHandler(void)
{
	Uns rd_index;
	for(;;)
	{
		//execute forward only when new GPS data received.
		SEM_pend(&SEM_GpsData,SYS_FOREVER);

		//assign longitude and latitude of PublicPositionData
		//convert original data of longitude and latitude of CurrGpsInfo to unit 0.001.
		SetGpsPosData();

		if(MyInfo.MMI_RdValid)
		{
			HWI_disable();
				MyInfo.MMI_RdValid=0;
			HWI_enable();

			//road information need to refresh in PublicPositionData when selecting a new line.
			//Previous station buffer should be clean.
			//pay attention to the situation of road index is equal to 0.
			rd_index = SearchRoadDataBase();
			//find out the station information of the selected road to RAM.
			Refresh_ST_ON_RD((Uns)rd_index);

			//refresh road information, when road index is equal to 0, nothing to do.
			RefreshRoadInfo(rd_index);

			if(!MyInfo.RoadLocked||MyInfo.LockedRoadIndex!=rd_index)
			{
				//clean ShangXiaXing information after road selection.
				MyInfo.ShangXiaXing = 0;

				//invalid the old next station in PublicPositionData.
				MyInfo.NxtStCnt=0;
				Dis_PRE_NXT_ST_ExceptPRE();
			}
			RoadLockTo(rd_index);
		}

		if(MyInfo.MMI_SelAbs&&!MyInfo.RoadLocked)
		{
			HWI_disable();
			MyInfo.MMI_SelAbs=0;
			HWI_enable();
			ToMMIData(Tx_Cmd_GPS_ExitAbs);
		}

		if(MyInfo.MMI_SelAbs==1)
		{
			HWI_disable();
			MyInfo.MMI_SelAbs=2;
			HWI_enable();
			ToMMIData(Tx_Cmd_GPS_EnterAbs);
		}

		if(MyInfo.MMI_SelAbs==3)
		{
			HWI_disable();
			MyInfo.MMI_SelAbs=0;
			HWI_enable();
			ToMMIData(Tx_Cmd_GPS_ExitAbs);
		}
		//MMI_UpDown is set by order or not.
		if(MyInfo.MMI_UpDown)
		{
			if(MyInfo.MMI_UpDown==0x01)
				MyInfo.ShangXiaXing=0x01;
			if(MyInfo.MMI_UpDown==0x02)
				MyInfo.ShangXiaXing=0x02;
			HWI_disable();
			MyInfo.MMI_UpDown==0x00;
			HWI_enable();
		}


		//time refresh needed.
		SearchStationDatabase();
		RefreshData();

		if (MyInfo.RoadLocked == ROAD_LOCKED)
			MyInfo.GpsLedF = MyInfo.GpsSts | (ROAD_LOCKED << 8);
		else
			MyInfo.GpsLedF = MyInfo.GpsSts;

		// renew RoadLocked
		// refresh ST_ON_RD
		// previous next station handle
		// renew PublicPositionData
		//search RegionDatabase
		SearchRegionDatabase();

		//lineAsking command handling function
		if(MyInfo.MMI_LineAskingFlag == 1)
		{
			HWI_disable();
			MyInfo.MMI_LineAskingFlag=0;
			HWI_enable();
			LineAskingCmdHandler();
		}

		//search QieHuanDatabase
		SearchQieHuanDatabase();

		GpsTimeHandler();

		if (PowOnFlag)
		{
			if (MyInfo.RoadLocked != ROAD_LOCKED)
			{
				ToMMIData(Tx_Cmd_GPS_InqueryRoad);
			}
			PowOnFlag = 0;
		}

		if(MyInfo.WorkSts == WORK_STATUS_GPS_SIMULATE)
		{
			if(MyInfo.SimulateSts == 2)
			   MyInfo.SimulateSts = 0;
		}
		MyInfo.GpsDataHandled=1;
	}
}
//Int1.4: XINT1--HC interrupt
#pragma CODE_SECTION(HWI_HC_XINT1_ISR, "FuncsMap2H0SARam")
void HWI_HC_XINT1_ISR(void)
{
  PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
  HcApp_Interrupt_Isr();
}

//Int2.4 : T1PINT--5KHz or 200us
#pragma CODE_SECTION(HWI_T1PINT_ISR, "FuncsMap2H0SARam")
void HWI_T1PINT_ISR(void)
{
  //Uns temp;

  // Enable more interrupts from this timer
  EvaRegs.EVAIMRA.bit.T1PINT = 1;
  EvaRegs.EVAIFRA.all = BIT7;
  // Acknowledge interrupt to receive more interrupts from PIE group 2
  PieCtrlRegs.PIEACK.all = PIEACK_GROUP2;

  if (MyInfo.PrgRdy < 2)
    return;
  /*temp = UART_RxTaxData();
  if (temp && (!MyInfo.RxTaxHead))
  {
    MyInfo.RxTaxHead = temp;
    SWI_post(&SWI_TaxData);
  }*/
}

//Int3.1 : T2PINT--0.1 second interrupt
//Count t0 10 to generate 1 Second system time.
#pragma CODE_SECTION(HWI_T2PINT_ISR, "FuncsMap2H0SARam")
void HWI_T2PINT_ISR(void)
{
  // Enable more interrupts from this timer
  EvaRegs.EVAIMRB.bit.T2PINT = 1;
  EvaRegs.EVAIFRB.all = BIT0;
  // Acknowledge interrupt to receive more interrupts from PIE group 3
  PieCtrlRegs.PIEACK.all = PIEACK_GROUP3;
  MyInfo.Tm10Hz++;
  if (MyInfo.Tm10Hz == 10){
    MyInfo.Tm10Hz = 0;
	IncTime((DATE_TIME_INFO *)&(AllTime.SysTime));
  }
}


void SWI_RxTaxData(void)
{
  TaxDataHandler();
  MyInfo.RxTaxHead = 0;
}









